From 4cdde7fabed0830b203c1d18ff569517b42e1b66 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 1 Feb 2015 15:21:15 -0800 Subject: [PATCH] Add a flag to force resolution of a fingerprint Previously if a fingerprint was considered fresh based on mtime, it would not get updated once a compilation finished with the new precise fingerprint (it would use the older fingerprint). This alters the `resolve` method to take a flag which disables this behavior and forces looking at the filesystem for a fingerprint. Closes #1259 --- src/cargo/ops/cargo_rustc/fingerprint.rs | 51 ++++++++++++------------ tests/test_cargo_compile_path_deps.rs | 7 ++-- tests/test_cargo_freshness.rs | 37 +++++++++++++++++ 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index 297173a31..f2adf8815 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -103,22 +103,25 @@ pub fn prepare_target<'a, 'b>(cx: &mut Context<'a, 'b>, pub struct Fingerprint { extra: String, deps: Vec, - personal: Personal, + local: LocalFingerprint, } #[derive(Clone)] -enum Personal { - Known(String), - Unknown(Path), +enum LocalFingerprint { + Precalculated(String), + MtimeBased(Option, Path), } impl Fingerprint { - fn resolve(&self) -> CargoResult { - let mut deps: Vec<_> = try!(self.deps.iter().map(|s| s.resolve()).collect()); + fn resolve(&self, force: bool) -> CargoResult { + let mut deps: Vec<_> = try!(self.deps.iter().map(|s| { + s.resolve(force) + }).collect()); deps.sort(); - let known = match self.personal { - Personal::Known(ref s) => s.clone(), - Personal::Unknown(ref p) => { + let known = match self.local { + LocalFingerprint::Precalculated(ref s) => s.clone(), + LocalFingerprint::MtimeBased(Some(n), _) if !force => n.to_string(), + LocalFingerprint::MtimeBased(_, ref p) => { debug!("resolving: {}", p.display()); try!(fs::stat(p)).modified.to_string() } @@ -173,26 +176,24 @@ fn calculate<'a, 'b>(cx: &mut Context<'a, 'b>, calculate(cx, p, t, kind) }).collect::>>()); - // And finally, calculate what our own personal fingerprint is - let personal = if use_dep_info(pkg, target) { + // And finally, calculate what our own local fingerprint is + let local = if use_dep_info(pkg, target) { let dep_info = dep_info_loc(cx, pkg, target, kind); - match try!(calculate_target_mtime(&dep_info)) { - Some(i) => Personal::Known(i.to_string()), - None => { - // If the dep-info file does exist (but some other sources are - // newer than it), make sure to delete it so we don't pick up - // the old copy in resolve() - let _ = fs::unlink(&dep_info); - Personal::Unknown(dep_info) - } + let mtime = try!(calculate_target_mtime(&dep_info)); + + // if the mtime listed is not fresh, then remove the `dep_info` file to + // ensure that future calls to `resolve()` won't work. + if mtime.is_none() { + let _ = fs::unlink(&dep_info); } + LocalFingerprint::MtimeBased(mtime, dep_info) } else { - Personal::Known(try!(calculate_pkg_fingerprint(cx, pkg))) + LocalFingerprint::Precalculated(try!(calculate_pkg_fingerprint(cx, pkg))) }; let fingerprint = Fingerprint { extra: extra, deps: deps, - personal: personal, + local: local, }; cx.fingerprints.insert(key, fingerprint.clone()); Ok(fingerprint) @@ -244,7 +245,7 @@ pub fn prepare_build_cmd(cx: &mut Context, pkg: &Package, kind: Kind, let new_fingerprint = Fingerprint { extra: String::new(), deps: Vec::new(), - personal: Personal::Known(new_fingerprint), + local: LocalFingerprint::Precalculated(new_fingerprint), }; let is_fresh = try!(is_fresh(&loc, &new_fingerprint)); @@ -287,7 +288,7 @@ pub fn prepare_init(cx: &mut Context, pkg: &Package, kind: Kind) fn prepare(is_fresh: bool, loc: Path, fingerprint: Fingerprint) -> Preparation { let write_fingerprint = Work::new(move |_| { debug!("write fingerprint: {}", loc.display()); - let fingerprint = try!(fingerprint.resolve().chain_error(|| { + let fingerprint = try!(fingerprint.resolve(true).chain_error(|| { internal("failed to resolve a pending fingerprint") })); try!(File::create(&loc).write_str(fingerprint.as_slice())); @@ -317,7 +318,7 @@ fn is_fresh(loc: &Path, new_fingerprint: &Fingerprint) -> CargoResult { }; let old_fingerprint = try!(file.read_to_string()); - let new_fingerprint = match new_fingerprint.resolve() { + let new_fingerprint = match new_fingerprint.resolve(false) { Ok(s) => s, Err(..) => return Ok(false), }; diff --git a/tests/test_cargo_compile_path_deps.rs b/tests/test_cargo_compile_path_deps.rs index 31d3ad185..9286d7ed2 100644 --- a/tests/test_cargo_compile_path_deps.rs +++ b/tests/test_cargo_compile_path_deps.rs @@ -1,4 +1,5 @@ -use std::old_io::{fs, File, USER_RWX}; +use std::old_io::{fs, File, USER_RWX, timer}; +use std::time::Duration; use support::{project, execs, main_file, cargo_dir}; use support::{COMPILING, RUNNING}; @@ -353,7 +354,7 @@ test!(deep_dependencies_trigger_rebuild { // // We base recompilation off mtime, so sleep for at least a second to ensure // that this write will change the mtime. - p.root().move_into_the_past().unwrap(); + timer::sleep(Duration::seconds(1)); File::create(&p.root().join("baz/src/baz.rs")).write_str(r#" pub fn baz() { println!("hello!"); } "#).unwrap(); @@ -366,7 +367,7 @@ test!(deep_dependencies_trigger_rebuild { COMPILING, p.url()))); // Make sure an update to bar doesn't trigger baz - p.root().move_into_the_past().unwrap(); + timer::sleep(Duration::seconds(1)); File::create(&p.root().join("bar/src/bar.rs")).write_str(r#" extern crate baz; pub fn bar() { println!("hello!"); baz::baz(); } diff --git a/tests/test_cargo_freshness.rs b/tests/test_cargo_freshness.rs index 407a04a94..a4d302a86 100644 --- a/tests/test_cargo_freshness.rs +++ b/tests/test_cargo_freshness.rs @@ -135,3 +135,40 @@ test!(rebuild_sub_package_then_while_package { assert_that(p.process(cargo_dir().join("cargo")).arg("build"), execs().with_status(0)); }); + +test!(changing_features_is_ok { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + authors = [] + version = "0.0.1" + + [features] + foo = [] + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(0) + .with_stdout("\ +[..]Compiling foo v0.0.1 ([..]) +")); + + assert_that(p.process(cargo_dir().join("cargo")).arg("build") + .arg("--features").arg("foo"), + execs().with_status(0) + .with_stdout("\ +[..]Compiling foo v0.0.1 ([..]) +")); + + assert_that(p.process(cargo_dir().join("cargo")).arg("build"), + execs().with_status(0) + .with_stdout("\ +[..]Compiling foo v0.0.1 ([..]) +")); + + assert_that(p.process(cargo_dir().join("cargo")).arg("build"), + execs().with_status(0) + .with_stdout("")); +}); -- 2.30.2